﻿Imports dooll.config
Imports System.Text.RegularExpressions

Public Class XmlTable
    Inherits System.Xml.XmlDocument
    Private mUriKey As String
    Private sKey As String = "ID"
    Private sCheckKey As String
    Private mUpdateColumns As Hashtable
    Private mErrMessage As String
    Private mReturnRowID As Integer
    Private mTextUpdateSql As String
    Private mBeforeUpdate As String
    Private mAfterUpdate As String
    Private debuglog As String = System.Web.HttpContext.Current.Server.MapPath("/debug.log")

#Region "自定义属性"
    Public ReadOnly Property ReturnRowID() As Integer
        Get
            Return mReturnRowID
        End Get
    End Property

    Public ReadOnly Property UpdateColumns() As Hashtable
        Get
            If mUpdateColumns Is Nothing Then
                mUpdateColumns = New Hashtable
            End If
            Return mUpdateColumns
        End Get
    End Property

    Public ReadOnly Property ErrMessage() As String
        Get
            Return mErrMessage
        End Get
    End Property

    ''' <summary>
    ''' 文本更新SQL语句
    ''' </summary>
    ''' <value>字符串</value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    ''' 
    Public ReadOnly Property TextUpdateSql() As String
        Get
            If mTextUpdateSql Is Nothing Then
                If DocumentElement Is Nothing OrElse UpdateColumns.Count = 0 OrElse mReturnRowID <= 0 Then
                    Return String.Empty
                End If

                If String.IsNullOrEmpty(PrimyKey) Then
                    mErrMessage = "数据表的Key主键未设定,请联系管理员!!"
                    Return Nothing
                End If

                Dim pkArray As String() = PrimyKey.Split(CChar("|"))

                Dim Sql, KeyCol As String
                Sql = String.Format("Update {0} Set ", TableName)

                For Each KeyCol In UpdateColumns.Keys
                    Sql = String.Format("{0} {1}='{2}',", Sql, KeyCol, Replace(CStr(mUpdateColumns.Item(KeyCol)), "'", "''"))
                Next

                If Sql.EndsWith(",") Then Sql = Sql.Substring(0, Sql.Length - 1)


                Dim strWhere As String = ""
                Dim el As System.Xml.XmlNode

                For iCount As Integer = 0 To pkArray.Length - 1
                    If pkArray(iCount).ToLower = "id" Then
                        strWhere = String.Format("and ID={0} ", mReturnRowID)
                    Else
                        el = DocumentElement.SelectSingleNode(String.Format("/{0}/{1}", TableName, pkArray(iCount)))
                        If Not el Is Nothing Then
                            strWhere = String.Format("{0}and {1}='{2}' ", strWhere, pkArray(iCount), el.InnerText.ToString)
                        End If
                    End If
                Next
                strWhere = CStr(IIf(strWhere.StartsWith("and"), String.Concat(" where ", strWhere.Substring(3)), strWhere))
                mTextUpdateSql = String.Concat(Sql, "  ", strWhere)
            End If
            Return mTextUpdateSql
        End Get
    End Property

    ''' <summary>
    ''' 用于更新的表名
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property TableName() As String
        Get
            If DocumentElement Is Nothing Then
                Return String.Empty
            End If
            Return DocumentElement.Name
        End Get
    End Property

    ''' <summary>
    ''' 关键词
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property PrimyKey() As String
        Get
            If DocumentElement Is Nothing Then
                Return String.Empty
            End If
            If DocumentElement.Attributes("key") Is Nothing Then
                Return String.Empty
            End If
            Return DocumentElement.Attributes("key").Value
        End Get

    End Property

    REM CheckWhere主键
    Public Property CheckColumn() As String
        Get
            Return sCheckKey
        End Get

        Set(ByVal value As String)
            sCheckKey = value
        End Set
    End Property

#End Region

    ''' <summary>
    ''' 验证内容
    ''' </summary>
    ''' <returns>true/false</returns>
    ''' <remarks></remarks>
    Public Function ValidContent() As Boolean
        Dim bIsVaild As Boolean = True
        Dim RegexText As String
        Dim s As String
        Dim xmlElement As System.Xml.XmlElement

        For Each xmlElement In DocumentElement.ChildNodes
            s = xmlElement.Name
            If s = "BeforeUpdate" Then
                mBeforeUpdate = xmlElement.InnerText
                DocumentElement.RemoveChild(xmlElement)
                Continue For
            End If
            If s = "AfterUpdate" Then
                mAfterUpdate = xmlElement.InnerText
                DocumentElement.RemoveChild(xmlElement)
                Continue For
            End If
            If Not xmlElement.Attributes("regex") Is Nothing Then
                RegexText = xmlElement.Attributes("regex").Value
                bIsVaild = Regex.IsMatch(xmlElement.InnerText, RegexText)
                If Not bIsVaild Then
                    If Not xmlElement.Attributes("message") Is Nothing Then
                        mErrMessage = xmlElement.Attributes("message").Value
                        xmlElement.RemoveAttribute("message")
                    Else
                        mErrMessage = "填写的字段不符合要求!!"
                    End If
                    Return bIsVaild
                End If
                xmlElement.RemoveAttribute("regex")
            End If
            If Not xmlElement.Attributes("message") Is Nothing Then
                xmlElement.RemoveAttribute("message")
            End If
            If Not xmlElement.Attributes("xtype") Is Nothing Then
                Select Case xmlElement.Attributes("xtype").Value.ToLower
                    Case "password"
                        xmlElement.InnerText = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(xmlElement.InnerText, "MD5").ToLower
                        xmlElement.RemoveAttribute("xtype")

                    Case "function"
                        Dim rtnStr As String = String.Empty
                        Using DataBase As New Data.MsSql
                            DataBase.doFunction(Split(xmlElement.InnerText, "|"), rtnStr)

                            xmlElement.InnerText = rtnStr
                            xmlElement.RemoveAttribute("xtype")
                            If Util.AppSettings("Debug") = "1" Then
                                Util.toLog(debuglog, "********************* function " & Now() & "*********************")
                                Util.toLog(debuglog, xmlElement.InnerText)
                                Util.toLog(debuglog, "-----------------------------------------------------------------")
                                Util.toLog(debuglog, DataBase.ErrMessage)
                            End If
                        End Using
                End Select
            End If

            REM 用于控制大文本更新
            If Not xmlElement.Attributes("textupdate") Is Nothing Then
                If xmlElement.Attributes("textupdate").Value = "sql" Then
                    UpdateColumns.Add(xmlElement.Name, xmlElement.InnerText)
                End If
            End If
        Next
        For Each xmlElement In DocumentElement.ChildNodes
            If Not xmlElement.Attributes("html") Is Nothing Then xmlElement.RemoveAttribute("html")
            If Not xmlElement.Attributes("textupdate") Is Nothing Then
                REM 移除大文件字节
                DocumentElement.RemoveChild(xmlElement)
            End If
        Next
        Return bIsVaild
    End Function

    ''' <summary>
    ''' 更新内容
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Update() As Integer
        If Not ValidContent() Then
            Return 101
        End If
        Dim ReturnValue As Integer
        Using DataBase As New Data.MsSql(mUriKey)
            If Not String.IsNullOrEmpty(mBeforeUpdate) Then
                ReturnValue = DataBase.UpdateEvent(Split(mBeforeUpdate, "|"), mErrMessage)
            End If
            If ReturnValue = 0 Then
                If Util.AppSettings("Debug") = "1" Then
                    Util.toLog(debuglog, "*********************" & Now() & "*********************")
                    Util.toLog(debuglog, OuterXml)
                    Util.toLog(debuglog, "-------------------------------------------------------")
                    Util.toLog(debuglog, TextUpdateSql)
                    Util.toLog(debuglog, CType(mReturnRowID, String))
                End If
                ReturnValue = DataBase.UpdateFromXml(OuterXml, mReturnRowID)
                If ReturnValue = 1 Or ReturnValue = 2 Then
                    REM 是否需要执行Sql 更新
                    If Not String.IsNullOrEmpty(TextUpdateSql) Then
                        If DataBase.ExecSql(TextUpdateSql) = -100 Then
                            mErrMessage = String.Format("执行更新的Sql语句出错({0}).", TableName)
                            Return -100
                        End If
                    End If

                    If Not String.IsNullOrEmpty(mAfterUpdate) Then
                        ReturnValue = DataBase.UpdateEvent(Split(mAfterUpdate, "|"), mErrMessage)
                    End If

                Else
                    mErrMessage = DataBase.ErrMessage
                End If
            End If

            Return ReturnValue
        End Using
    End Function

    Protected Overrides Sub Finalize()
        mUpdateColumns = Nothing
        MyBase.Finalize()
    End Sub

    Public Sub New(ByVal UriKey As String)
        mUriKey = UriKey
    End Sub
End Class

